#pragma once

#include "lg_def.h"
#include "lg_conf.h"
#include "lg_math.h"
#include "lg_enum.h"

typedef struct LGBackend LGBackend;
typedef struct LGWindow LGWindow;
typedef struct LGList LGList;

typedef struct LGVertex LGVertex;
typedef struct LGTexture LGTexture;
typedef struct LGShader LGShader;
typedef struct LGMaterial LGMaterial;
typedef struct LGCanvas LGCanvas;

typedef void (*LGRefFree)(void* ref);
typedef struct LGRef LGRef;

typedef struct {
    unsigned width;
    unsigned height;
    unsigned x;
    unsigned y;
    void (*onEvt)(LGWindow*, LGWindowEvt);
}LGWindowStyle;

typedef struct {
    int type;
    int offset;
}LGVertexAttr;


typedef struct {
    unsigned count;
    unsigned offset;
    LGMaterial* material;
    LGVertex* vertex;
    LGMatrix transform;
}LGDraw;


LG_API int
lgInit(LGConfig* config, LGBackend* backend);
LG_API void
lgDefault(LGConfig* config);
LG_API int
lgDispatch();

LG_API LGWindow*
lgOpenWindow(const char* title, LGWindowStyle* style, void* ud);
LG_API int
lgCloseWindow(LGWindow* window);
LG_API void
lgGetWindowSize(LGWindow* window, unsigned* w, unsigned* h);
LG_API void
lgRenderWindow(LGWindow* window, LGCanvas* canvas);
LG_API void
lgOnWindowEvt(LGWindow* window, void (*onEvt)(LGWindow*, LGWindowEvt));

LG_API LGVertex*
lgNewVertex(LGVertexAttr* attrs,
    unsigned attrCount, unsigned eleSize, unsigned cap);
LG_API void
lgClearVertex(LGVertex* vertex);
LG_API void
lgClearVertexCap(LGVertex* vertex);
LG_API void
lgPushVertexData(LGVertex* vertex, void* p, unsigned count);
LG_API void
lgPushVertexIndexs(LGVertex* vertex, unsigned* p, unsigned count);
LG_API void
lgUploadVertex(LGVertex* vertex);
LG_API unsigned
lgGetVetexTotalData(LGVertex* vertex);
LG_API unsigned
lgGetVetexTotalIndex(LGVertex* vertex);

LG_API LGTexture*
lgNewTexture(unsigned width, unsigned height, LGTexFormat format);
LG_API LGTexture*
lgNewPngTexture(const char* data, size_t size);
LG_API void
lgFreeTexture(LGTexture* tex);
LG_API int
lgUploadTexture(LGTexture* tex,
    int format, unsigned rect[4], const void* data);
LG_API void
lgTextureFilter(LGTexture* tex,
    LGTexFilter minFilter, LGTexFilter maxFilter);
LG_API void
lgTextureWrap(LGTexture* tex,
    LGTexWrap sWrap, LGTexWrap tWrap);


LG_API void
lgDrawPoints(LGCanvas* canvas, LGFloat size, LGDraw* draw);
LG_API void
lgDraw(LGCanvas* canvas, LGDraw* draw);

LG_API LGShader*
lgNewShader();
LG_API int
lgShaderSource(LGShader* shader,
    LGShaderType type, const char* data, size_t size);
LG_API int
lgCompileShader(LGShader* shader, const char** err);

LG_API LGMaterial*
lgNewMaterial(LGShader* shader);
LG_API void
lgMaterialShader(LGMaterial* material, LGShader* shader);
LG_API unsigned
lgRegUniformF(LGMaterial* material, const char* name, LGFloat f);
LG_API unsigned
lgRegUniformV(LGMaterial* material, const char* name, LGVector* v);
LG_API unsigned
lgRegUniformM(LGMaterial* material, const char* name, LGMatrix* m);
LG_API unsigned
lgRegUniformTex(LGMaterial* material, const char* name, LGTexture* tex);
LG_API unsigned
lgRegUniformCanvas(LGMaterial* material, const char* name, LGCanvas* canvas);
LG_API void
lgSetUniformF(LGMaterial* material, unsigned index, LGFloat f);
LG_API void
lgSetUniformV(LGMaterial* material, unsigned index, LGVector* v);
LG_API void
lgSetUniformM(LGMaterial* material, unsigned index, LGMatrix* m);
LG_API void
lgSetUniformTex(LGMaterial* material, unsigned index, LGTexture* tex);
LG_API void
lgSetUniformCanvas(LGMaterial* material, unsigned index, LGCanvas* canvas);
LG_API void
lgSetDepthTest(LGMaterial* material, LGDepthTest depthTest);
LG_API void
lgSetDrawType(LGMaterial* material, LGDrawType type);

LG_API LGCanvas*
lgNewCanvas(unsigned width, unsigned height);
LG_API void
lgResizeCanvas(LGCanvas* canvas, unsigned width, unsigned height);
LG_API void
lgSetCanvasColor(LGCanvas* canvas, LGVector* color);
LG_API void
lgClearCanvas(LGCanvas* canvas);
LG_API void
lgSetCanvasProjection(LGCanvas* canvas, LGMatrix* proj);
LG_API void
lgSetCanvasView(LGCanvas* canvas, LGMatrix* view);


LG_API void*
lgNewRef(size_t size, LGRefFree free);
LG_API void
lgFreeRef(void* ref);
LG_API void
lgRetainRef(void* ref);
LG_API void
lgReleaseRef(void* ref);
LG_API unsigned
lgCountRef(void* ref);

LG_API LGShader*
lgNewStdShader(LGStdShader e);
LG_API const char**
lgStdShaderSource(LGStdShader e);
LG_API LGVertex*
lgNewStdVertex(unsigned cap);
LG_API unsigned
lgPushStdVertexRect(LGVertex* vertex, LGVector* size,
    LGVector* color, unsigned indexOffset, LGMatrix* transform);
LG_API unsigned
lgPushStdVertexBox(LGVertex* vertex, LGVector* size,
    LGVector* color, unsigned indexOffset, LGMatrix* transform);

LG_API LGList*
lgNewList(size_t size, unsigned cap);
LG_API void
lgFreeList(LGList* list);
LG_API void
lgPushList(LGList* list, void* p, unsigned count);
LG_API void
lgClearList(LGList* list);
LG_API void
lgClearListCap(LGList* list);
LG_API unsigned
lgGetListTotal(LGList* list);
LG_API void
lgBeginList(LGList* list);
LG_API int
lgNextList(LGList* list, void** p, unsigned* count);